package com.jjy.ideaplugin;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SM4;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.JBUI;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.jjy.ideaplugin.Contant.*;

/**
 * 公共代码
 *
 * @author jinjiayu 2024/10/11
 */
public class CommonService {
    public static Project project;
    /**
     * 保存的历史秘钥列表
     */
    private static final Map<String, java.util.List<String>> HISTORY_MAP = new HashMap();

    public static void commonActionPerformed(AnActionEvent event, String type, String title, String jLabel1, String jLabel2, String jLabel3) {
        try {
            project = event.getData(CommonDataKeys.PROJECT);

            // 创建表单面板
            JPanel formPanel = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();

            // 文字展示
            addComponent(formPanel, gbc, 0, new JLabel(jLabel1));

            // 输入框-key
            JTextField jTextField = new JTextField();
            addComponent(formPanel, gbc, 1, jTextField);

            // 文字展示
            addComponent(formPanel, gbc, 2, new JLabel("可以选择一个保存的历史秘钥"));

            // 下拉框
            showCustomComboBoxDialog(formPanel, gbc, jTextField, type);

            // 文字展示
            addComponent(formPanel, gbc, 5, new JLabel(jLabel2));

            // 输入框-需要加密的数据
            JBTextField textField2 = new JBTextField();
            addComponent(formPanel, gbc, 6, textField2);

            // 文字展示
            addComponent(formPanel, gbc, 7, new JLabel(jLabel3));

            // 输入框-需要解密的数据
            JBTextField textField3 = new JBTextField();
            addComponent(formPanel, gbc, 8, textField3);

            // 创建按钮,点击后执行加解密操作
            JTextField resultField = new JTextField();
            JButton resultButton = new JButton("执行加/解密");
            resultButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // 点击按钮后的操作
                    run(jTextField, resultField, textField2.getText(), textField3.getText(), type);
                }
            });
            JPanel runJPanel = new JPanel();
            runJPanel.add(resultButton);
            addComponent(formPanel, gbc, 9, runJPanel);

            // 文字展示-加解密结果
            addComponent(formPanel, gbc, 10, new JLabel("加/解密结果是:"));

            // 输入框-结果展示
            addComponent(formPanel, gbc, 11, resultField);

            // 文字展示-什么都不展示,暂时只是为了占一行
            addComponent(formPanel, gbc, 12, new JLabel());

            // 关闭弹框-OK
            int result = JOptionPane.showConfirmDialog(
                    null,
                    formPanel,
                    title,
                    JOptionPane.OK_CANCEL_OPTION,
                    JOptionPane.QUESTION_MESSAGE
            );
            if (result == JOptionPane.OK_OPTION) {
                // TODO 点击OK等于关闭弹窗,暂时什么也不做
            }

        } catch (Exception e) {
            e.printStackTrace();

            StringBuilder error = new StringBuilder();
            error.append(e.toString()).append("\n");
            for (StackTraceElement element : e.getStackTrace()) {
                error.append("\tat ").append(element).append("\n");
            }
            Messages.showMessageDialog(project, error.toString(), "出错啦!!!", Messages.getInformationIcon());
        }
    }

    /**
     * 执行加/解密操作
     * 参考文档: 无
     *
     * @param
     * @return
     * @author jinjiayu 2024/10/13
     */
    public static void run(JTextField keyTextField, JTextField resultTextField, String content1, String content2, String type) {
        try {
            String key = keyTextField.getText();
            String encrypt = "";
            String decrypt = "";
            String emptyMsg = "";
            String errorMsgJustOne = "待加密数据和待解密数据只能二选一,不要一起填!";
            String errorMsg = "你的算法类型搞错啦!只能是SM2或SM4";
            String resultContent;
            if (StringUtils.isNotBlank(content1) && StringUtils.isNotBlank(content2)) {
                resultContent = errorMsgJustOne;
            } else {
                if ("SM2".equals(type)) {
                    encrypt = StringUtils.isNotBlank(content1) ? encryptSM2(content1, key) : emptyMsg;
                    decrypt = StringUtils.isNotBlank(content2) ? decryptSM2(content2, key) : emptyMsg;
                } else if ("SM4".equals(type)) {
                    encrypt = StringUtils.isNotBlank(content1) ? encryptSM4(content1, key) : emptyMsg;
                    decrypt = StringUtils.isNotBlank(content2) ? decryptSM4(content2, key) : emptyMsg;
                } else {
                    Messages.showMessageDialog(project, "当前算法暂不支持!", "出错啦~~~", Messages.getInformationIcon());
                }
                resultContent = StringUtils.isNotBlank(encrypt) ? encrypt : (StringUtils.isNotBlank(decrypt) ? decrypt : errorMsg);
            }

            // 复制加解密结果到剪贴板
            copyToClipboard(resultContent);

            // 将结果展示到新的弹框中
            //Messages.showMessageDialog(project, message, "结果(已经复制到您的剪贴板啦~~)", Messages.getInformationIcon());
            // 将结果展示到输入框中
            resultTextField.setText(resultContent);
        } catch (Exception e) {
            e.printStackTrace();

            StringBuilder error = new StringBuilder();
            error.append(e.toString()).append("\n");
            for (StackTraceElement element : e.getStackTrace()) {
                error.append("\tat ").append(element).append("\n");
            }
            Messages.showMessageDialog(project, error.toString(), "出错啦,你确定你的秘钥没写错么?", Messages.getInformationIcon());
        }
    }


    public static void showCustomComboBoxDialog(JPanel formPanel, GridBagConstraints gbc, JTextField jTextField, String type) {
        JComboBox<String> comboBox;
        JButton addButton;
        JButton deleteButton;

        List<String> historyList = HISTORY_MAP.get(type);
        if (CollectionUtils.isEmpty(historyList)){
            historyList = new ArrayList<>();
            HISTORY_MAP.put(type, historyList);
        }

        // 创建组合下拉框
        comboBox = new ComboBox<>(historyList.toArray(new String[0]));
        comboBox.setEditable(true);
        // 设置最大显示行数
        comboBox.setMaximumRowCount(10);

        // 创建按钮
        addButton = new JButton("保存秘钥");
        deleteButton = new JButton("删除当前秘钥");

        // 添加新增按钮监听器
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addHistoryItem(comboBox, jTextField, type);
            }
        });

        // 添加删除按钮监听器
        deleteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                deleteHistoryItem(comboBox, type);
            }
        });

        // 添加组合下拉框框监听器
        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String selectedItem = (String) comboBox.getSelectedItem();
                if (selectedItem != null) {
                    jTextField.setText(selectedItem);
                }
            }
        });

        // 创建按钮面板
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(addButton);
        buttonPanel.add(deleteButton);

        // 添加下拉框到面板
        addComponent(formPanel, gbc, 3, comboBox);

        // 添加按钮到面板
        gbc.gridx = 0;
        gbc.gridy = 4;
        // 左对齐
        gbc.anchor = GridBagConstraints.WEST;
        // 添加内边距
        gbc.insets = JBUI.insets(5);
        formPanel.add(buttonPanel, gbc);
    }

    /**
     * 添加组件(文字展示,输入框,下拉框等)
     * 参考文档: 无
     *
     * @param
     * @return
     * @author jinjiayu 2024/10/13
     */
    public static void addComponent(JPanel formPanel, GridBagConstraints gbc, int gridy, Component component){
        gbc.gridx = 0;
        gbc.gridy = gridy;
        // 左对齐
        gbc.anchor = GridBagConstraints.WEST;
        // 水平填充(拓展整行)
        gbc.fill = GridBagConstraints.HORIZONTAL;
        // 添加内边距
        gbc.insets = JBUI.insets(5);
        formPanel.add(component, gbc);
    }

    /**
     * 添加新秘钥
     * 参考文档: 无
     *
     * @param
     * @return
     * @author jinjiayu 2024/10/13
     */
    private static void addHistoryItem(JComboBox<String> comboBox, JTextField inputField, String type) {
        List<String> history = HISTORY_MAP.get(type);
        String input = inputField.getText().trim();
        if (history.contains(input)) {
            Messages.showMessageDialog(project, "请勿重复添加!", "结果", Messages.getInformationIcon());
        }
        if (!input.isEmpty() && !history.contains(input)) {
            history.add(input);
            comboBox.addItem(input);
            Messages.showMessageDialog(project, "添加秘钥成功!", "结果", Messages.getInformationIcon());
        }
    }

    /**
     * 删除当前秘钥
     * 参考文档: 无
     *
     * @param
     * @return
     * @author jinjiayu 2024/10/13
     */
    private static void deleteHistoryItem(JComboBox<String> comboBox, String type) {
        List<String> history = HISTORY_MAP.get(type);
        String selectedItem = (String) comboBox.getSelectedItem();
        if (CollectionUtils.isEmpty(history)) {
            Messages.showMessageDialog(project, "没有数据可以删啦!", "结果", Messages.getInformationIcon());
        }
        if (selectedItem != null) {
            history.remove(selectedItem);
            comboBox.removeItem(selectedItem);
            Messages.showMessageDialog(project, "删除秘钥成功!", "结果", Messages.getInformationIcon());
        }
    }

    /**
     * 复制内容到剪切板
     * 参考文档: 无
     *
     * @param
     * @return
     * @author jinjiayu 2024/10/13
     */
    private static void copyToClipboard(String text) {
        System.out.println("复制到剪切板:" + text);
        StringSelection stringSelection = new StringSelection(text);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(stringSelection, null);
    }

    /**
     * SM2加密
     * 参考文档: 无
     *
     * @param content
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String encryptSM2(String content, String sm2Publickey) {
        String key = StringUtils.isBlank(sm2Publickey) ? SM2PUBLICKEY : sm2Publickey;
        SM2 sm2 = SmUtil.sm2(null, key);
        byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
        return sm2.encryptBase64(bytes, KeyType.PublicKey);
    }

    /**
     * SM2解密
     * 参考文档: 无
     *
     * @param content
     * @param sm2Privatekey
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String decryptSM2(String content, String sm2Privatekey) {
        String key = StringUtils.isBlank(sm2Privatekey) ? SM2PRIVATEKEY : sm2Privatekey;
        SM2 sm2 = SmUtil.sm2(key, null);
        return sm2.decryptStr(content, KeyType.PrivateKey);
    }

    /**
     * SM2加密
     * 参考文档: 无
     *
     * @param content
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String encryptSM2(String content) {
        SM2 sm2 = SmUtil.sm2(SM2PRIVATEKEY, SM2PUBLICKEY);
        byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
        return sm2.encryptBase64(bytes, KeyType.PublicKey);
    }

    /**
     * SM2解密
     * 参考文档: 无
     *
     * @param content
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String decryptSM2(String content) {
        SM2 sm2 = SmUtil.sm2(SM2PRIVATEKEY, null);
        return sm2.decryptStr(content, KeyType.PrivateKey);
    }

    /**
     * SM4加密
     * SM4的秘钥key如果是16进制的字符串,必须要使用HexUtil.decodeHex(key)来转换,而不是key.getBytes()
     * 参考文档: 无
     *
     * @param content
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String encryptSM4(String content, String sm4key) {
        String key = StringUtils.isBlank(sm4key) ? SM4KEY : sm4key;
        SM4 sm4 = SmUtil.sm4(HexUtil.decodeHex(key));
        return sm4.encryptBase64(content);
    }

    /**
     * SM4解密
     * SM4的秘钥key如果是16进制的字符串,必须要使用HexUtil.decodeHex(key)来转换,而不是key.getBytes()
     * 参考文档: 无
     *
     * @param content
     * @param sm4key
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String decryptSM4(String content, String sm4key) {
        String key = StringUtils.isBlank(sm4key) ? SM4KEY : sm4key;
        SM4 sm4 = SmUtil.sm4(HexUtil.decodeHex(key));
        return sm4.decryptStr(content);
    }

    /**
     * SM4加密
     * SM4的秘钥key如果是16进制的字符串,必须要使用HexUtil.decodeHex(key)来转换,而不是key.getBytes()
     * 参考文档: 无
     *
     * @param content
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String encryptSM4(String content) {
        SM4 sm4 = SmUtil.sm4(HexUtil.decodeHex(SM4KEY));
        return sm4.encryptBase64(content);
    }

    /**
     * SM4解密
     * SM4的秘钥key如果是16进制的字符串,必须要使用HexUtil.decodeHex(key)来转换,而不是key.getBytes()
     * 参考文档: 无
     *
     * @param content
     * @return String
     * @author jinjiayu 2024/10/11
     */
    public static String decryptSM4(String content) {
        SM4 sm4 = SmUtil.sm4(HexUtil.decodeHex(SM4KEY));
        return sm4.decryptStr(content);
    }


    public static void main(String[] args) {
        String content = "我是明文";

        // SM2
        String encryptSM2 = encryptSM2(content);
        //String encryptSM2 = "BK3wyQ7/CclQhxKnk8SjpM4EvaCIG1/oldToTAxG7SOzlYGrknNwJkhJpFuskHtu1QrDRKf9ho1wqOUeT5wLeijhOWmxLp9BdyYuAxaZ76ZPekI546g0Egc9lWlswr32gBUExEMr3QMQ/OWAFhBidewJbOZAzZmaps/ISwb8k9l9/1TlTTxzazxFclzCLg==";
        System.out.println("SM2加密后的密文encryptSM2 = " + encryptSM2);
        String decryptSM2 = decryptSM2(encryptSM2);
        System.out.println("SM2解密后的明文decryptSM2 = " + decryptSM2);

        // SM4
        String encryptSM4 = encryptSM4(content);
        //String encryptSM4 = "4vTnrl7roALTUSTdMkQdPZ8Uhbezi47LfUJ8Hf75cEFpXW5PSv6sScy85Rdrs8Rzzp/qEuqYi4XI0/zElAd6o4I5/VFs23aT+ljkzp4r9IM=";
        System.out.println("SM4加密后的密文encryptSM4 = " + encryptSM4);
        String decryptSM4 = decryptSM4(encryptSM4);
        System.out.println("SM4解密后的明文decryptSM4 = " + decryptSM4);
    }
}
